<?php
// This file is part of Preg question type - https://code.google.com/p/oasychev-moodle-plugins/
//
// Preg question type is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Contains source info for generation of lexer.
 * @package    qtype_preg
 * @copyright  2012 Oleg Sychev, Volgograd State Technical University
 * @author     Penskoy Nikita <nik95penik@yandex.ru>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

defined('MOODLE_INTERNAL') || die();
//require_once($CFG->dirroot . '/question/type/preg/tohtml.php');
require_once($CFG->dirroot . '/question/type/poasquestion/jlex.php');
require_once($CFG->dirroot . '/question/type/preg/treger/bison.php');
require_once($CFG->dirroot . '/question/type/preg/preg_unicode.php');

function paint($text,$num)  {;}

%%
%class qtype_preg_lexer
%function nextToken
%char
%line
%unicode
%state SEQ

WHITESPACE = [\x09\x0A\x0B\x0C\x0D\x20\x85\xA0] // Whitespace character.
TODIP = [^"\"«»()[]-,.!;: "0-9\n\t]

%{
    public $comment='';
    public function column() {
        return $this->yycol;
    }
    public function line() {
        return $this->yyline;
    }
%}

%%    

<YYINITIAL> ","?{WHITESPACE}*"или" {
// Alternative.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ALTERNATIVE,null,$this->line(),$this->column()); 
}

<YYINITIAL> [оО]"дин"{WHITESPACE}+"из" {
// Another form for alternative.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ONEOF,null,$this->line(),$this->column());
}

<YYINITIAL> [лЛ]"юбой"{WHITESPACE}+"из" {
// Chararacter set.        
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ANYOF,null,$this->line(),$this->column());
}

<YYINITIAL> [лЛ]"юбой"{WHITESPACE}+"символ,"{WHITESPACE}*"кроме" {
// Negative character set.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ANYEXCEPTOF,null,$this->line(),$this->column());
}

<YYINITIAL> ([гГ]"руппа")|([пП]"одмаска")    {
// Group.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::GROUP,null,$this->line(),$this->column());
}

<YYINITIAL> "то,"{WHITESPACE}*"что"{WHITESPACE}+"совпало"{WHITESPACE}+"с"{WHITESPACE}+("группой"|"подмаской") { 
// Find matches with group.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::FIND,null,$this->line(),$this->column());
}

<YYINITIAL> [еЕ]"сли"{WHITESPACE}+"было"{WHITESPACE}+"совпадение"{WHITESPACE}+"с"{WHITESPACE}+("группой"|"подмаской") {
// Condition for match with group.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::IFM,null,$this->line(),$this->column());
}

<YYINITIAL> ","{WHITESPACE}*"то"{WHITESPACE} {
// Then.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::THEN,null,$this->line(),$this->column());
}

<YYINITIAL> ","{WHITESPACE}*"иначе"{WHITESPACE} {
// Else.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ELSEM,null,$this->line(),$this->column());
}

<YYINITIAL> ("повтор"("ить"|"ять"|"ение"|"ы")?{WHITESPACE}+)?[0-9]+({WHITESPACE}+"раз""а"?) {
// Repeat exact number of times.
    paint($this->yytext(),1);
    $tostrfunc = new qtype_preg_unicode;
    preg_match('/[0-9]+/',$this->yytext(),$number);
    return new JLexToken(qtype_preg_parser::NUMBER,$number[0],$this->line(),$this->column());
}

<YYINITIAL> ("повтор"("ить"|"ять"|"ение"|"ы")?{WHITESPACE}+)?(("хотя"{WHITESPACE}+"бы")|("не"{WHITESPACE}+"менее")|("более")|("от")){WHITESPACE}+[0-9]+({WHITESPACE}+"раз""а"?)? {
// Left bound to repeat.
    paint($this->yytext(),1);
    $tostrfunc = new qtype_preg_unicode;
    preg_match('/[0-9]+/',$this->yytext(),$number);
    if($tostrfunc->strpos($this->yytext(),'более')!==false) {
        $number[0]++;
    }
    return new JLexToken(qtype_preg_parser::FROM,$number[0],$this->line(),$this->column());    
}

<YYINITIAL> ("повтор"("ить"|"ять"|"ение"|"ы")?{WHITESPACE}+)?(("не"{WHITESPACE}+"более")|("до")|("менее")){WHITESPACE}+[0-9]+({WHITESPACE}+"раз""а"?) {
// Right bound to repeat.
    paint($this->yytext(),1);
    $tostrfunc = new qtype_preg_unicode;
    preg_match('/[0-9]+/',$this->yytext(),$number);
    if($tostrfunc->strpos($this->yytext(),'менее') !== false) {
        $number[0]--;
    }
    return new JLexToken(qtype_preg_parser::TO,$number[0],$this->line(),$this->column());    
}

<YYINITIAL> [мМ]"ожет"{WHITESPACE}+"быть" {
// ? in regexp.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::MAYBE,null,$this->line(),$this->column());
}

<YYINITIAL> ","{WHITESPACE}*"наименьшее" {
// Nogreed version.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::NOGREED,null,$this->line(),$this->column());
}
        
<YYINITIAL> "("    {
// (.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::LP,null,$this->line(),$this->column());
}

<YYINITIAL> ")" {
// ).
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::RP,null,$this->line(),$this->column());;    
}

<YYINITIAL> "[" {
// [.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::LB,null,$this->line(),$this->column());
}

<YYINITIAL> "]"    {
// ].
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::RB,null,$this->line(),$this->column());
}

<YYINITIAL> ([сС]"начала")|([вВ]{WHITESPACE}*"начале")|([нН]"ачинается"{WHITESPACE}+("с"{WHITESPACE})?)|([сС]"перва")|([пП]"ерв"("ым"|"ая"|"ый"|"ое")) {
// ^ in regexp.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::BEG,null,$this->line(),$this->column());
}

<YYINITIAL> ([вВ]{WHITESPACE}+"конце")|([зЗ]"аканчива"("я"|"ет"|"ется"|"ются"))|([пП]"оследн"("ий"|"им"|"ая"|"ее"))| {
// $ in regexp.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::ATEND,null,$this->line(),$this->column());
}

<YYINITIAL> ("на"{WHITESPACE}+)?"границ"("а"|"е"){WHITESPACE}+"слова" {
// /b in regexp.
    paint($this->yytext(),1);    
    return new JLexToken(qtype_preg_parser::BOUND,null,$this->line(),$this->column());
}

<YYINITIAL> "нет"{WHITESPACE}+"границы"{WHITESPACE}+"слова" {
// /B in regexp.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::NOTBOUND,null,$this->line(),$this->column());
}

<YYINITIAL> ([,.!;:]+)|([зЗ]"атем")|([пП]"отом")|([сС]"ледом")|([дД]"алее")|([пП]"осле")|([вВ]"след"{WHITESPACE}+"за"{WHITESPACE}+"этим")|([вВ]{WHITESPACE}+"дальнейшем") {
// Concatenation.
    paint($this->yytext(),1);
    return new JLexToken(qtype_preg_parser::CONCAT,null,$this->line(),$this->column());
}

<YYINITIAL> {WHITESPACE} {
// Space symbols
}        

<YYINITIAL> (("\""[0-9]"\"")|([0-9])){WHITESPACE}*"-"{WHITESPACE}*(("\""[0-9]"\"")|([0-9])) {
// Number diapason.
    $tostrfunc = new qtype_preg_unicode;
    $diapason = preg_replace('/["\""\x09\x0A\x0B\x0C\x0D\x20\x85\xA0]+/','',$this->yytext());
    return new JLexToken(qtype_preg_parser::DIAPASON,$diapason,$this->line(),$this->column());
}

<YYINITIAL> (("\""{TODIP}"\"")|{TODIP}){WHITESPACE}*"-"{WHITESPACE}*(("\""{TODIP}"\"")|{TODIP}) {
// Character diapason.
    $tostrfunc = new qtype_preg_unicode;
    $diapason = preg_replace('/["\""\x09\x0A\x0B\x0C\x0D\x20\x85\xA0]+/','',$this->yytext());
    return new JLexToken(qtype_preg_parser::DIAPASON,$diapason,$this->line(),$this->column());
}

<YYINITIAL> "%%temp"[0-9]+ {
// Template for this programm.
    paint($this->yytext(),3);
    return new JLexToken(qtype_preg_parser::TEMPLATE,substr($this->yytext(),6),$this->line(),$this->column());
}

<YYINITIAL> « {
//
    $this->yybegin(self::SEQ);
    paint($this->yytext(),1);
}

<YYINITIAL> "\"" {
//
    $this->yybegin(self::SEQ);
    paint($this->yytext(),1);
}

<SEQ> [^\\\n»"\""]+ {
//
    $this->comment .= $this->yytext();
}

<SEQ> \\n {
//
    $this->comment .= "\n";
}     
<SEQ> \\\\ {
//
    $this->comment .= '\\';
}

<SEQ> \\» {
//
    $this->comment .= '"';
}

<SEQ> "\\\"" {
//
    $this->comment .= '\"';
}

<SEQ> "»" {
//
    $this->yybegin(self::YYINITIAL);
    paint($this->comment,2);
    paint($this->yytext(),1);
    $rew = $this->comment;
    $this->comment = '';
    return new JLexToken(qtype_preg_parser::CONSTANT,$rew,$this->line(),$this->column());
}

<SEQ> "\"" {
//
    $this->yybegin(self::YYINITIAL);
    paint($this->comment,2);
    paint($this->yytext(),1);
    $rew = $this->comment;
    $this->comment = '';
    return new JLexToken(qtype_preg_parser::CONSTANT,$rew,$this->line(),$this->column());
}

<YYINITIAL> (("букв"("а"|"ы"))|("слов"("о"|"а"))){WHITESPACE}+{TODIP}+ {    
// Constant with prefix.
    $tostrfunc = new qtype_preg_unicode;
    $comment = $tostrfunc->substr($this->yytext(),6);
    $comment = trim($comment);
    paint(substr($this->yytext(),0,6),0);
    paint($comment,2); 
    return new JLexToken(qtype_preg_parser::CONSTANT,$comment,$this->line(),$this->column());
}

<YYINITIAL> [^"\"«»()[\],.!;: "\n\t]+    {
//
    paint($this->yytext(),2);
    return new JLexToken(qtype_preg_parser::CONSTANT,$this->yytext(),$this->line(),$this->column());
}